package com.google.coffeeshop.business;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import vn.bang.utility.DateUtil;
import vn.bang.utility.JpaUtil;

import com.google.coffeeshop.GeneralConstants;
import com.google.coffeeshop.dao.DAOFactory;
import com.google.coffeeshop.entity.EmployeeDTO;
import com.google.coffeeshop.entity.OrderDTO;
import com.google.coffeeshop.entity.OrderLineDTO;
import com.google.coffeeshop.entity.ProductDTO;
import com.google.coffeeshop.entity.ProductGroupDTO;
import com.google.coffeeshop.entity.ProductSellingPriceDTO;
import com.google.coffeeshop.entity.SeatDTO;
import com.google.coffeeshop.log.Log;

public class OrderBusiness extends AbstractBaseBusiness {

	static public void cancelOrder(long seatId) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
			List<OrderDTO> orders = DAOFactory.createOrderDAO(entityManager).findAllBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			if (orders != null && !orders.isEmpty()) {
				for (OrderDTO order : orders) {
					if (order.getSeat() != null && seatId == order.getSeat().getId()) {
						changeOrderStatus(order.getId(), GeneralConstants.ORDER_DEACTIVE_STATUS, entityManager);
					}
				}
			}
			changeSeatStatus(seatId, GeneralConstants.SEAT_USABLE_STATUS, entityManager);
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		
	}
	
	static public EmployeeDTO findEmployeeBySeatId(Long seatId) {
		final EntityManager entityManager = createEntityManager();
		try {
			OrderDTO order = DAOFactory.createOrderDAO(entityManager).findBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			if (order != null) {
				return order.getEmployee();
			}
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return null;
	}
	
	static public List<SeatDTO> findAllBusySeats() {
		List<SeatDTO> seats = new ArrayList<SeatDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			seats.addAll(DAOFactory.createSeatDAO(entityManager).findByStatus(GeneralConstants.SEAT_BUSY_STATUS));
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return seats;
	}
	
	static public List<SeatDTO> findAllUsableSeats() {
		List<SeatDTO> seats = new ArrayList<SeatDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			seats.addAll(DAOFactory.createSeatDAO(entityManager).findByStatus(GeneralConstants.SEAT_USABLE_STATUS));
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return seats;
	}
	
	static public List<EmployeeDTO> findAllEmployeesWorking() {
		List<EmployeeDTO> employees = new ArrayList<EmployeeDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			employees.addAll(DAOFactory.createEmployeeDAO(entityManager).findAllWorking());
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return employees;
	}
	
	static public List<SeatDTO> findAllSeats() {
		List<SeatDTO> seats = new ArrayList<SeatDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			seats.addAll(DAOFactory.createSeatDAO(entityManager).findAll());
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return seats;
	}
	
	static public void orderStuff(long seatId, long employeeId, long productId, long orderQuantity) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);

			OrderDTO order = DAOFactory.createOrderDAO(entityManager).findBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			if (order == null) {
				order = createNewOrder(entityManager, seatId, employeeId, productId);
			}
			order = makeOrder(entityManager, order, productId, orderQuantity);
			updateOrderAmount(entityManager, order);
			changeToBusyStatus(entityManager, seatId);
			
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}
	
	static public void returnStuff(long seatId, long employeeId, long productId, long returnQuantity) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);

			OrderDTO order = DAOFactory.createOrderDAO(entityManager).findBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			if (order == null) {
				return;
			}
			order = returnOrder(entityManager, order, productId, returnQuantity);
			updateOrderAmount(entityManager, order);
			
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}
	
	private static OrderDTO returnOrder(EntityManager entityManager, OrderDTO order, long productId, long returnQuantity) {
		OrderLineDTO orderLine = findOrderLineByProductId(order.getOrderLines(), productId);
		if (orderLine != null) {
			long realReturnQuantity = orderLine.getQuantity() >= returnQuantity ? returnQuantity : orderLine.getQuantity();
			orderLine.setQuantity(orderLine.getQuantity() - realReturnQuantity);
			warehousingProduct(orderLine.getProduct(), realReturnQuantity);
			if (orderLine.getQuantity() == 0) {
				DAOFactory.createOrderLineDAO(entityManager).remove(orderLine);
				order.getOrderLines().remove(orderLine);
			}
		}
		return order;
	}
	
	private static void warehousingProduct(ProductDTO product, long quantity) {
		product.setInventory(product.getInventory() + quantity);
	}
	
	private static OrderDTO makeOrder(EntityManager entityManager, OrderDTO order, long productId, long orderQuantity) {
		OrderLineDTO orderLine = findOrderLineByProductId(order.getOrderLines(), productId);
		if (orderLine != null) {
			orderLine.setQuantity(orderLine.getQuantity() + orderQuantity);
			consumeProduct(orderLine.getProduct(), orderQuantity);
			
		} else {
			OrderLineDTO newOrderLine = createNewOrderLine(entityManager, productId, orderQuantity);
			if (newOrderLine != null) {
				order.getOrderLines().add(newOrderLine);
				consumeProduct(newOrderLine.getProduct(), orderQuantity);
				newOrderLine.setOrder(order);
			}
			order = DAOFactory.createOrderDAO(entityManager).merge(order);
		}
		return order;
	}
	
	private static void consumeProduct(ProductDTO product, long quantity) {
		product.setInventory(product.getInventory() - quantity);
	}
	
	private static void updateOrderAmount(EntityManager entityManager, OrderDTO order) {
		if (order != null && !order.getOrderLines().isEmpty()) {
			long amount = 0;
			for (OrderLineDTO orderLine : order.getOrderLines()) {
				amount += orderLine.getQuantity() * orderLine.getPriceOfUnit();
			}
			order.setAmount(amount);
			DAOFactory.createOrderDAO(entityManager).save(order);
		}
	}
	
	private static void changeToBusyStatus(EntityManager entityManager, long seatId) {
		SeatDTO seat = DAOFactory.createSeatDAO(entityManager).find(seatId);
		if (seat != null) {
			seat.setStatus(GeneralConstants.SEAT_BUSY_STATUS);
			DAOFactory.createSeatDAO(entityManager).merge(seat);
		}
	}
	
	private static OrderDTO createNewOrder(EntityManager entityManager, long seatId, long employeeId, long productId) {
		OrderDTO order = new OrderDTO();
		order.setCreateDate(DateUtil.getNow());
		order.setCode(CodeGenerationBusiness.getOrderCode()); // should generation auto
		order.setEmployee(DAOFactory.createEmployeeDAO(entityManager).find(employeeId));
		order.setSeat(DAOFactory.createSeatDAO(entityManager).find(seatId));
		order.setAmount(0);
		order.setStatus(GeneralConstants.ORDER_UNPROCESSED_STATUS);
		return order;
	}
	
	private static OrderLineDTO createNewOrderLine(EntityManager entityManager, long productId, long orderQuantity) {
		ProductDTO product = DAOFactory.createProductDAO(entityManager).find(productId);
		if (product == null) {
			return null;
		}
		
		ProductSellingPriceDTO productPrice = DAOFactory.createProductPriceDAO(entityManager).findLastestPriceByProductId(productId);
		if (productPrice == null) {
			return null;
		}
		
		OrderLineDTO orderLine = new OrderLineDTO();
		orderLine.setProduct(product);
		orderLine.setPriceOfUnit(productPrice.getPrice());
		orderLine.setQuantity(orderQuantity);
		orderLine.setServed(Boolean.FALSE);
		return orderLine;
	}
	
	private static OrderLineDTO findOrderLineByProductId(List<OrderLineDTO> orderLines, long productId) {
		if (orderLines != null && !orderLines.isEmpty()) {
			for (OrderLineDTO orderLine : orderLines) {
				if (orderLine.getProduct() != null && orderLine.getProduct().getId() != null) {
					if (orderLine.getProduct().getId().equals(productId)) {
						return orderLine;
					}
				}
			}
		}
		return null;
	}
	
	static public OrderLineDTO findOrderLineByProductId(long orderId, long productId) {
		final EntityManager entityManager = createEntityManager();
		try {
			OrderDTO order = DAOFactory.createOrderDAO(entityManager).find(orderId);
			if (order != null) {
				return findOrderLineByProductId(order.getOrderLines(), productId); 
			}
			
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return null;
	}
	
	static public List<ProductGroupDTO> findAllProductGroups() {
		List<ProductGroupDTO> productGroups = new ArrayList<ProductGroupDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			productGroups.addAll(DAOFactory.createProductGroupDAO(entityManager).findAll());
			
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return productGroups;
	}
	
	static public OrderLineDTO findOrderLineById(long orderLineId) {
		final EntityManager entityManager = createEntityManager();
		try {
			return DAOFactory.createOrderLineDAO(entityManager).find(orderLineId);
			
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return null;
	}
	
	static public List<ProductDTO> findAllProductsByGroupId(long groupId) {
		List<ProductDTO> products = new ArrayList<ProductDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			ProductGroupDTO group = DAOFactory.createProductGroupDAO(entityManager).find(groupId);
			if (group != null) {
				products.addAll(DAOFactory.createProductDAO(entityManager).findActiveByGroupId(groupId));
			}
			
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} catch(NullPointerException nullPointerException) {
			Log.error("Product not found in groupId = " + groupId, nullPointerException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return products;
	}
	
	static public List<OrderLineDTO> findOrderLines(long seatId) {
		List<OrderLineDTO> orderLines = new ArrayList<OrderLineDTO>();
		final EntityManager entityManager = createEntityManager();
		try {
			OrderDTO order = DAOFactory.createOrderDAO(entityManager).findBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			if (order != null) {
				orderLines = order.getOrderLines();
			}
			
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return orderLines;
	}
	
	static public OrderDTO findOrder(long seatId) {
		OrderDTO order = null;
		final EntityManager entityManager = createEntityManager();
		try {
			order = DAOFactory.createOrderDAO(entityManager).findBySeatId(seatId, GeneralConstants.ORDER_UNPROCESSED_STATUS);
			
		} catch(PersistenceException persistenceException) {
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return order;
	}
	
	static public void saveSeat(SeatDTO seatDTO) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
				DAOFactory.createSeatDAO(entityManager).save(seatDTO);
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}
	
	static public void saveOrderLine(OrderLineDTO orderLines) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
				DAOFactory.createOrderLineDAO(entityManager).save(orderLines);
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}
	
	static public void saveOrderLines(List<OrderLineDTO> orderLines) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
				DAOFactory.createOrderLineDAO(entityManager).saveAll(orderLines);
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}
	
	static public ProductDTO findProduct(long productId) {
		ProductDTO productDTO = new ProductDTO();
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
				productDTO = DAOFactory.createProductDAO(entityManager).find(productId);
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
		return productDTO;
	}

	public static void removeOrderLine(long orderLineId) {
		final EntityManager entityManager = createEntityManager();
		try {
			JpaUtil.beginTransaction(entityManager);
				OrderLineDTO orderLine = DAOFactory.createOrderLineDAO(entityManager).find(orderLineId);
				DAOFactory.createOrderLineDAO(entityManager).remove(orderLine);
			JpaUtil.commitEntityManager(entityManager);
		} catch(PersistenceException persistenceException) {
			JpaUtil.rollbackEntityManager(entityManager);
			Log.error(persistenceException);
		} finally {
			JpaUtil.closeEntityManager(entityManager);
		}
	}
	
}
